package com.fzz.learnitservice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.commonfzz.pojo.po.R;
import com.commonfzz.tools.IdGenerator;
import com.fzz.learnitservice.mapper.UserMapper;
import com.fzz.learnitservice.pojo.dto.LoginDTO;
import com.fzz.learnitservice.pojo.dto.RegisterDTO;
import com.fzz.learnitservice.pojo.po.User;
import com.fzz.learnitservice.pojo.vo.LoginVo;
import com.fzz.learnitservice.service.IUserService;
import com.fzz.learnitservice.utils.JwtUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * <p>
 * 用户信息 服务实现类
 * </p>
 *
 * @author 小菜钊
 * @since 2025-10-23
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    private final UserMapper userMapper;
    private final PasswordEncoder passwordEncoder;
    private final RedisTemplate<String, String> redisTemplate;
    private final JwtUtils jwtUtils;


    /**
     * 用户注册
     * @param registerDTO
     * @return
     */
    @Override
    public R register(RegisterDTO registerDTO) {
        String username = registerDTO.getUsername();
        String email = registerDTO.getEmail();

        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(User::getUsername, username)
                .or()
                .eq(User::getEmail, email);
        long count = userMapper.selectCount(wrapper);
        if(count > 0) {
            throw new RuntimeException("用户名或邮箱已存在");
        }

        User user = new User();
        BeanUtil.copyProperties(registerDTO, user);
        Long userId = new IdGenerator(10, 12).nextId();

        user.setId(userId);
        user.setPassword(passwordEncoder.encode(user.getPassword()));

        userMapper.insert(user);
        return R.ok();
    }


    /**
     * 用户端登录
     * @param loginDTO
     * @return
     */
    @Override
    public R<LoginVo> login(LoginDTO loginDTO) {
        String account = loginDTO.getAccount();
        String password = loginDTO.getPassword();

        // 1. 根据账号查询用户（用户名或邮箱）
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", account).or().eq("email", account);
        User user = userMapper.selectOne(wrapper);

        if (user == null) {
            throw new RuntimeException("账号不存在");
        }

        // 2. 校验密码（假设密码已用BCrypt加密）
        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new RuntimeException("密码错误");
        }

        // 3. 生成 JWT
        String accessToken = jwtUtils.generateToken(user.getId(), user.getUsername());

        // 4. 返回登录信息
        LoginVo loginVo = new LoginVo();
        BeanUtil.copyProperties(user, loginVo);
        loginVo.setAccessToken(accessToken);

        return R.ok(loginVo);
    }

    /**
     * 用户端退出
     * @param userId
     * @return
     */
    @Override
    public R logout(Long userId) {
        String redisKey = "login:token:" + userId;
        redisTemplate.delete(redisKey);
        return R.ok();
    }


    /**
     * 用户设置英语水平
     * @param enLevel
     * @param userId
     * @return
     */
    @Override
    public R setEnLevel(int enLevel, long userId) {
        Set<Integer> validLevels = new HashSet<>(Arrays.asList(2, 3, 4, 5, 6, 7, 8, 9, 10));
        if(!validLevels.contains(enLevel)) {
            throw new RuntimeException("该英语水平待开发，请选择其他选项");
        }

        UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
        userUpdateWrapper.lambda().eq(User::getId, userId).set(User::getEnglishLevel, enLevel);

        int result = userMapper.update(null, userUpdateWrapper);
        return result > 0 ? R.ok() : R.error("修改失败");
    }

}
